package com.zhanghe.security.filter;

import com.google.gson.Gson;
import com.zhanghe.security.property.SecurityProperties;
import com.zhanghe.security.service.SimpleUserDetailsService;
import com.zhanghe.security.util.JwtUtil;
import com.zhanghe.security.util.R;
import com.zhanghe.security.util.ResponseUtil;
import com.zhanghe.security.util.ReturnCode;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class AuthcationFilter extends OncePerRequestFilter {

    protected static final Logger logger = LoggerFactory.getLogger(AuthcationFilter.class);

    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private SimpleUserDetailsService simpleUserDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        logger.debug("进入token验证过滤器");
        ResponseUtil.setOrigins(httpServletRequest,httpServletResponse,securityProperties.getOrigins());
        String accessToken = httpServletRequest.getHeader("access-token");
        String refreshToken = httpServletRequest.getHeader("refresh-token");
        logger.debug("accessToken:{}",accessToken);
        logger.debug("refreshToken:{}",refreshToken);
        if(refreshToken==null||"".equals(refreshToken)){
            //请求没带refreshtoken
            if (accessToken==null||"".equals(accessToken)){
                //请求没带accessToken

            }else{
                //请求中带上了access_token
                try{
                    Gson gson = new Gson();
                    String user = JwtUtil.getSubject(accessToken,securityProperties.getTokensecret()).toString();
                    ArrayList<GrantedAuthority> authorities = new ArrayList<>();
                    String rolestr = JwtUtil.getValue(accessToken,securityProperties.getTokensecret(),"roles").toString();
                    for(String role: (List<String>)gson.fromJson(rolestr, List.class)){
                        authorities.add( new SimpleGrantedAuthority(role) );
                    }
                    SecurityContextHolder.getContext()
                            .setAuthentication(new UsernamePasswordAuthenticationToken(user, null, authorities));
                    logger.debug("用户[{}]拥有权限:{}",user,rolestr);
                }catch (ExpiredJwtException e){
                    logger.debug("accessToken过期,过期token:{}",accessToken);
                    R r = new R(ReturnCode.ACCESS_TOKEN_EXPIRE);
                    ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                    return;
                }catch (SignatureException e){
                    logger.error("accessToken验证不通过,token:{}",accessToken);
                    R r = new R(ReturnCode.SIGNATURE_FAILED);
                    ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                    return;
                }catch (Exception e){
                    logger.error("accessToken不合法,token:{}",accessToken);
                    R r = new R(ReturnCode.TOKEN_ERROR);
                    ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                    return;
                }
            }
        }else{
            //请求带了refreshtoken
            try {
                String user = JwtUtil.getSubject(refreshToken, securityProperties.getTokensecret()).toString();
                UserDetails userDetails = simpleUserDetailsService.loadUserByUsername(user);

                SecurityContextHolder.getContext()
                        .setAuthentication(new UsernamePasswordAuthenticationToken(user, null, userDetails.getAuthorities()));
                logger.debug("用户[{}]通过refreshToken重新登录", user);
            }catch (ExpiredJwtException e){
                logger.debug("refreshtoken过期,过期token:{}",accessToken);
                R r = new R(ReturnCode.REFRESH_TOKEN_EXPIRE);
                ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                return;
            }catch (SignatureException e){
                logger.error("refreshtoken验证不通过,token:{}",accessToken);
                R r = new R(ReturnCode.SIGNATURE_FAILED);
                ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                return;
            }catch (Exception e){
                logger.error("refreshtoken不合法,token:{}",accessToken);
                R r = new R(ReturnCode.TOKEN_ERROR);
                ResponseUtil.writeResponse(httpServletRequest,httpServletResponse,r.toString(),securityProperties.getOrigins());
                return;
            }
        }
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}
